package ReflectionTest;

import java.lang.annotation.ElementType;
import java.lang.reflect.*;

public class ReflectionTest {
    public static void main(String[] args) {
        try {
            // baseTest();
            // getClassTest();
            classType();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void getClassTest() throws ClassNotFoundException {
        // 1. 通过类名获取Class对象
        Class personClass1 = User.class;
        System.out.println(personClass1.hashCode());
        // 2. 通过运行时对象获取Class对象
        User p = new User();
        Class personClass2 = p.getClass();
        System.out.println(personClass2.hashCode());
        // 3. 通过Class对象获取Class对象
        Class personClass3 = Class.forName("ReflectionTest.Person");
        System.out.println(personClass3.hashCode());
        // 4. 通过类加载器获取Class对象
        ClassLoader classLoader = ReflectionTest.class.getClassLoader();
        Class personClass4 = classLoader.loadClass("ReflectionTest.Person");
        System.out.println(personClass4.hashCode());
    }

    public static void baseTest() throws NoSuchMethodException, SecurityException, InstantiationException,
            IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchFieldException {
        // 1. 获取Class对象
        Class<User> personClass = User.class;
        // 2. 获取构造器
        Constructor<User> p1Constructor = personClass.getConstructor();
        // 3. 通过构造器实例创建对象
        User p1 = p1Constructor.newInstance();
        System.out.println(p1);

        // 2. 获取带参构造器
        Constructor<User> p2Constructor = personClass.getConstructor(String.class, int.class);
        // 3. 通过构造器实例创建对象
        User p2 = p2Constructor.newInstance("Tom", 20);
        System.out.println(p2);

        // 2. 获取私有构造器 - getDeclaredConstructor: 获取所有构造器，包括私有的
        Constructor<User> p3Constructor = personClass.getDeclaredConstructor(String.class);
        // 3. 通过构造器实例创建对象
        p3Constructor.setAccessible(true);
        User p3 = p3Constructor.newInstance("Jerry");
        System.out.println(p3);

        // 4. 调用类的属性、方法
        // 4.1 调用属性
        // 4.1.1 获取公有属性
        Field nameField = personClass.getField("name");
        // 4.1.2 设置属性值，需要传入对象和属性值
        nameField.set(p1, "Jack");
        System.out.println(p1);
        // 4.1.3 获取属性值
        System.out.println(nameField.get(p1));
        // 4.1.4 获取私有属性
        Field ageField = personClass.getDeclaredField("age");
        ageField.setAccessible(true);
        ageField.set(p1, 30);
        System.out.println(p1);

        // 4.2 调用方法
        // 4.2.1 获取公有方法
        Method showMethod = personClass.getMethod("show");
        showMethod.invoke(p1);
        // 4.2.2 获取私有方法，需要设置可访问性，第一个参数是方法名，第二个参数是方法参数类型列表
        Method displayMethod = personClass.getDeclaredMethod("display", String.class);
        displayMethod.setAccessible(true);
        displayMethod.invoke(p1, "Hello");
    }

    public static void classType() {
        Class s1 = Object.class;
        Class s2 = Comparable.class;
        Class s3 = String[].class;
        Class s4 = int[][].class;
        Class s5 = ElementType.class;
        Class s6 = Override.class;
        Class s7 = int.class;
        Class s8 = void.class;
        Class s9 = Class.class;
        int[] a = new int[10];
        int[] b = new int[100];
        Class s10 = a.getClass();
        Class s11 = b.getClass();
        // 只要数组的元素类型与维度一样，就是同一个 Class
        System.out.println(s10 == s11);
    }
}
